Module-level declarations
Types
An auth handler defines who can and should call a specific operation. A new auth handler should be defined for each operation in the dapp.
This struct represents default auth descriptor configurations that can be used by the client to create credentials that can access the account. These configurations can be defined by the dapp developer by extending the login_config
function.
When a user tries to log into a dapp, a login auth descriptor will be created using one of these configurations, and the signer will be stored in such a way that allows the client to sign all transactions it's allowed to without asking for user confirmation.
Using this feature allows the client to provide a better user experience, since the client will be allowed to call what the dapp considers non-sensitive operations.
Proper configuration is required to avoid allowing sensitive operations to be called by the login keypairs that are accessible to the client.
The arguments of the evm_auth
operation
configuration used by the auth module, as defined in the chromia.yml
file
Similar to accounts.rule_variable
, but it adds two more variables that only make sense in the context of login auth descriptors:
relative_block_time
is the difference in timestamp between the auth descriptor creation and its expirationrelative_block_height
is the difference in block number between the auth descriptor creation and its expiration
These two variables are not useful for normal auth descriptors, as those are created at the same time of definition. In the case of login auth descriptors, the definition happens during the dapp development, while they're created anytime a user logs in. This allows the developer to define rules like a time to live for the login sessions.
Properties
tag used in auth message construction which will be replaced with the authorizing account ID
The constant that defines app level authentication scope. If scope is omitted when defining an auth handler, then it has 'app' scope, i.e. it is used to authenticate operations that do not have their own auth handlers if there is no mount point auth handler for the operation.
tag used in auth message construction which will be replaced with the authenticating auth descriptor ID
tag used in auth message construction which will be replaced with blockchain RID
The name of the default login configuration. This will be used when none is specified
size of a byte_array representing an EVM address, in bytes
name of the operation used to authorize through EVM signatures
name of the operation used to authorize through FT signatures
size of a byte_array representing an FT pubkey, in bytes
tag used in auth message construction which will be replaced with the unique nonce
This prefix could appear before an auth handler's scope to mark that it can be overridden. If two auth handlers are found with the same scope, but one has the override prefix, the other one is used.
Functions
Given a message, a valid EVM signature will add some information to it prior to hashing it and cryptographically signing. This function returns the hash of the message as per the EVM signature specifications in EIP-191.
Given the message and signature, extracts the evm address that signed it.
Throws "INPUT ERROR"
if message is empty.
Verifies that the signer of a certain message is the signer of the single-sig auth descriptor used to authorize this operation.
Throws "INPUT ERROR"
if the signature is null
Throws "INVALID SIGNATURE"
when the signature verification fails. This might happen if:
the message signer is not the one associated with the auth descriptor
the message that was signed does not correspond to the one passed in the
message
parameter
Throws if the message is empty
Verifies that the arguments passed to the evm_auth
operation are valid.
Throws "INPUT ERROR"
if the param passed in auth_args
has any number of elements other than three.
Throws "UNAUTHORIZED ACCESS"
if the auth descriptor does not have the necessary flags to authorize this operation.
Verifies that the signature found in the evm_auth
operation is valid to authorize the operation being called.
Throws if the signature cannot be validated. The most common reasons include:
the auth handler for
op
is not foundthe signer is not registered in the auth descriptor
too few signers signed the operation, in case of a multisig auth descriptor
the signer signed the wrong message
the auth descriptor does not give sufficient permissions for the operation that is being called
Verifies that the signature found in the ft_auth
operation is valid to authorize the operation being called.
Can only be called from an operation.
Throws if the signature cannot be validated. Common reasons include:
the signers of the auth descriptor did not sign this transaction
too few signers signed the operation, in case of a multisig auth descriptor
the auth descriptor does not give sufficient permissions for the operation that is being called
Verifies that the message has been authorized by the multi-sig auth descriptor. This implies that the signatures list contains enough signatures to reach the minimum amount of signatures required, and that all signatures are from valid signers from the auth descriptors
Throws "MISMATCHED SIGNER"
if a signature is found to be out of place. They must be in the same order they were registered in when the auth descriptor was first created.
Throws "INSUFFICIENT SIGNERS"
if the number of valid signatures was below the signature required threshold.
Throws if a signer signed the wrong message, or if the message is empty.
Utility function that allows easily adding an auth handler. It should be used by dapps, while library developers should generally prefer using add_overridable_auth_handler
instead, allowing dapps to override the default handler.
Throws if scope
is not valid
Example:
operation my_op() { ... }
@extend(auth.auth_handler)
function () = auth.add_auth_handler(
rell.meta(my_op).mount_name,
flags,
message_function,
resolver_function
);
Utility function to help extend the login_config
function.
Example usage:
@extend(auth.login_config)
function () = add_login_config(name, flags, rules);
Like add_auth_handler
, but the auth handler here defined will not be used if a different auth handler for the same scope was created with add_auth_handler
.
As normal, however, for an operation with mount point a.b.operation
, an overridable auth handler with scope a.b
will take precedence over a non-overridable auth handler with scope a
Throws if scope
is not valid
This function can be extended by users to add custom logic after the authentication of an operation.
Throws when any extension of this function throws.
Extendable function used to define auth handlers. When called it returns a map of all auth handlers defined in the dapp.
The map pairs up the auth handlers with their scopes.
Throws if any extension of this function throws.
calls authenticate_and_return_context and returns just the account
Verifies that:
the transaction is properly signed
the signer(s) is allowed to call that operation in the name of an account
the account is not currently rate limited
For point 2, auth flags of the auth descriptor that signed the operation are checked.
This function expects to find an auth operation before the one we're currently in. That operation receives as parameters the account the user wants to access, and the auth descriptor that allows them to access it.
Given that information, this function checks that the requirements for the current operation (found in the _auth_handler
) are satisfied.
Can only be called from an operation.
The code of this function can be expanded by the developers by extending either of before_authenticate
and after_authenticate
.
Throws "MISSING AUTH OP"
if there is no previous operation in the transaction, or it is not an auth operation.
Throws "INVALID AUTH DESCRIPTOR"
if the authenticating auth descriptor is not accepted by the _auth_handler
's resolver
.
Throws "EXPIRED AUTH DESCRIPTOR"
if the auth descriptor used to authenticate has expired.
Throws when the user is for some reason not allowed to call this operation. The most common reasons include:
the account the user wants to access does not exist
the auth descriptor that the user uses to authenticate does not exist, or it is not attached to the account that is being accessed
the account does not have enough rate limit points
the rules for the auth descriptor cannot be parsed
the requirements for the operation cannot be found
the auth descriptor does not give the user sufficient permissions given the operation's requirements
any additional requirement added by extending the
before_authenticate
andafter_authenticate
functions is infringed.any part of the
_auth_handler
is broken (the message is improperly formatted, or either of the two functions found in themessage_formatter
orresolver
fields throw)
This function can be extended by users to add custom logic before the authentication of an operation.
Throws when any extension of this function throws.
Creates the message that should be signed on an EVM wallet to approve the given operation.
Throws "MISCONFIGURED MESSAGE"
if the template doesn't have a nonce placeholder or a blockchain RID placeholder, both of which should be added to the template in advance by utils.make_auth_message
Extracts the account ID and auth descriptor ID from the args of the auth operation, which are the operations supported by is_auth_op
Extracts the account ID passed to the auth operation, which is any operation supported by is_auth_op
.
Throws "INVALID AUTH OP"
if the operation passed is not an auth operation
Throws "INVALID AUTH ARGS"
if the auth operation passed has no arguments
Extracts the account and account_auth_descriptor
from the args of the auth operation, which is one of the operations supported by is_auth_op
.
Throws if the account referred to in auth_args
does not exist
Throws "MISSING AUTH DESCRIPTOR"
if the auth descriptor referred to in auth_args
is not associated with the account id specified in auth args or does not exist altogether.
Creates message from operation name and arguments. It is used when evm_auth
is used to authenticate a user, but auth message is not specified in the auth handler of the operation.
The message will contain the operation name and all parameters, formatted in a way that favors readability of every parameter. It is not expected to be a sensible message for end users to read, as the parameters will not have a label identifying what they represent.
Retrieves the account and auth descriptor ID from the auth operation that precedes the current operation, if any. Returns null if no operation precedes the current one, or it is not an auth operation.
Can only be called from an operation.
Returns the flags needed to call a certain operation.
Throws if the auth handler for op_name
cannot be found.
Finds the auth handler for the provided operation name among all the auth handlers defined in this dapp as extensions of auth_handler
.
All auth handlers will be in a map<scope: text, _auth_handler>
A scope can be:
an operation name, in the way it is called from the client:
a.b.my_op
an operation name prefixed with
OVERRIDE_PREFIX
:OVERRIDE_PREFIX + "a.b.my_op"
a mount point:
a.b
the value of
APP_SCOPE
When calling an operation, the auth handler that will be used is (in this order):
the auth handler with the operation name as scope, if it exists
the auth handler with the operation name and
OVERRIDE_PREFIX
as scope, if it existsthe auth handler with the closest mount point as scope, if it exists
the auth handler with the app scope, if it exists
For example, an operation mounted on a.b.my_op
will look for, in this order:
the auth handler with scope
a.b.my_op
the auth handler with scope
OVERRIDE_PREFIX + "a.b.my_op"
the auth handler with scope
a.b
the auth handler with scope
a
the auth handler with the app scope
Throws if op_name
is not valid
Throws "MISSING HANDLER"
if no auth handler is defined for this operation, nor any mount point above it.
Returns the auth message template that is needed to authorize a certain operation, given its arguments. It will either use the one defined in auth_handler.message_formatter
, or create a default one from the args if the former does not exist.
Throws if the auth handler for op_name
cannot be found.
Retrieves the signers and signatures from the evm_signatures
operation. Returns empty lists if the operation is not found.
Can only be called from an operation.
Throws "MISMATCHED SIGNATURES"
if the length of the two lists is mismatched in the evm_signatures
operation.
Throws "NULL EVM SIGNATURE"
if any signature is null.
Calculates the best auth descriptor to use for the given account when calling the given operation with the given arguments. It assumes that the auth descriptors have all the required auth flags.
If the operation has an auth handler with a resolver function, it will be used to decide which auth descriptor to return. Otherwise, the first auth descriptor on the list will be returned.
If no auth descriptor is returned but ad_ids
is not empty, the auth handler resolver function is to blame.
Throws if the auth handler for this operation is not found or its resolver is a function that throws.
Like get_first_allowed_auth_descriptor
, but instead of accepting a list of auth descriptors it takes a list of accounts.auth_descriptor_signer
IDs. The list of auth descriptors to check will be the list of all the auth descriptors these signers participate in, provided that they can be used for authenticating this operation (i.e., they have the necessary flags to allow them).
Throws if the auth handler for this operation is not found or its resolver is a function that throws.
Retrieves the auth handler that should be applied to the given operation name, only looking through mount scope auth handlers.
Example: If the operation a.b.my_op
is passed, it will return the first auth handler found from this list:
an auth handler with scope
a.b
an auth handler with scope
a
null regardless of whether an auth handler with scope
a.b.my_op
exists.
Checks whether auth operations cannot be used with provided operation.
Auth operations don't perform any checks, which means that if they're used with an operation that does not call authenticate
, users could pass a lot of signatures to it without being rate limited.
For example, they could send evm_auth
followed by a nop
, and no logic would be performed on chain. However, the transaction would be stored, allowing a malicious user to store a lot of data on chain very quickly (since rate limiting doesn't take place).
The next operation thus be one that either rate limits or checks the auth operation in some way.
Throws "AUTH OP PARSING ERROR"
if the chromia.yml
cannot be parsed for this parameter, e.g. if some elements are not text or there are duplicates.
Verifies whether the operation passed is an auth operation, that is one of:
EVM_AUTH_OP
FT_AUTH_OP
Checks whether evm_signatures
operation can be used with provided operation.
We don't keep track of nonce for keys used with evm_signatures
, therefore if not used with care, authorizing an operation with evm_signatures
could lead to replay attack.
In order to use it with an operation, the operation has to be whitelisted. By default, library only allows evm_signatures
to be used with certain operations.
evm_signatures
is safe to use in combination with ft_auth
or evm_auth
operation.
However, if used as only way to authorize an operation, the operation has to ensure that it cannot be called more than once with same parameters.
One way to avoid that is if the operation creates an entity that has some key
value that is derived from operation parameters.
Throws "EVM SIG PARSING ERROR"
if the chromia.yml
cannot be parsed for this parameter, e.g. if some elements are not text or there are duplicates.
Verifies whether the operation passed is evm_signatures
Utility function that builds a mount scope given all the parts of it and a number indicating the depth. Example: join_text_list(["a", "b", "c"], 2)
outputs "a.b"
Throws "INPUT ERROR"
if:
count is 0, or
count is greater or equal to the
components
size
This function can be extended by users to add custom login configurations.
Throws if any extension of this function throws.
Converts a list of rule_expression
to a complex rule that can be used inside an auth descriptor's rules
field
Throws "EMPTY RULES"
if the rules_list
is empty
Alias for map_rule
Converts a rule_expression
to a gtv config that can be used inside an auth descriptor's rules
field.
Same as accounts.block_height
, but using the relative rule variable.
Same as accounts.block_time
, but using the relative rule variable.
Ensures that this operation is authorizing an operation which is whitelisted for usage with evm_signatures
The operation that is being authorized should be the next operation in the transaction, but it's allowed to have an auth operation or a strategy operation between this operation and the authorized one.
Throws "EVM SIG FORBIDDEN"
if:
the operation that is being authorized is not whitelisted,
there's no operation after this one, or
there is only one operation after this one, and it's an auth or strategy operation
Can only be called from an operation, and it should only be called by evm_signatures
Verifies that the next operation is one that will make use of the auth operation that is being called.
Can only be called from an operation, and it should only be called by auth operations.
Throws "AUTH OP FORBIDDEN"
if the next operation is blacklisted or this is the last operation in the transaction
Verifies that the scope name is valid, i.e. that it matches this regex: /^\w+(\.\w+)*$/
any single word (matched by \w+
) or sequence of such words separated by dots is valid. name
may not start or end with a dot.
Throws "INVALID SCOPE"
if the name does not match
Retrieves an account_auth_descriptor
given the account it's associated with and the ID of the auth descriptor itself. Returns null if not found.
Ensures that the scope is valid, also trimming leading and trailing whitespace.
Throws if scope
is not valid
Verifies whether provided list of signers have signed the operation/transaction. FT (GTX) signers are checked against GTX signers
and signatures
fields, while EVM signers are checked against signers and signatures provided in external.auth.evm_signatures
operation. Only used when the signers are not part of an auth descriptor, for example when an auth descriptor is being registered.
Can only be called from an operation.
Throws "MISSING AUTH OP"
when no auth operation is found to be preceding the current one but the message template requires the account and/or auth descriptor ID that would be found there.
Throws if the auth handler for the current operation cannot be found.
Throws if the signers cannot be verified. Common cases are:
the EVM signers and signatures in
evm_signers
are in different ordersome EVM signers have not signed the message, or any of them have signed a wrong message
some FT signers did not sign the transaction
the message for the EVM signers was empty
Does what verify_signers
does, but receives the message as a parameter instead of using the auth message of the current operation.
Can only be called from an operation.
Throws "MISMATCHED SIGNATURES"
if any of the signers and signatures on the evm_signatures
operation don't match in the exact order they're found.
Throws "MISSING SIGNATURE"
if:
an EVM signer is specified but the signature is not found in the
evm_signatures
operation.an FT signer is specified but the signature is not found in the signers of the transaction.
Throws "UNSUPPORTED SIGNER"
if a signer passed is neither an EVM nor an FT signer, which means the byte array length is different from EVM_ADDRESS_SIZE
and FT_PUBKEY_SIZE
Throws if the message is empty.
Throws if any signatures in evm_signatures
is null or missing, or if there's extra signatures in that operation.